#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

#include <net/if.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define UDP_PORT 50001
#define TCP_PORT 50002

struct file_info
{
    char name[32];
    int size;
};

int main(int argc, char const *argv[]) // ./sendfile IP file
{
    if(argc != 3)
    {
        printf("请指定对方的IP和你要发送的文件\n");
        exit(0);
    }

    int udpfd = socket(AF_INET, SOCK_DGRAM, 0);  // 收发文件的基本信息
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0); // 收发文件的具体内容

    // 准备好对方的地址
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    bzero(&addr, len);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(UDP_PORT);


    // 使用UDP给对方发去文件的基本信息
    struct file_info info;
    len = sizeof(addr);
    bzero(&info, sizeof(info));

    // 取得要发送的文件的基本信息
    const char *realname = strrchr(argv[2], '/');
    realname = (realname==NULL) ? argv[2] : realname+1;
    strcpy(info.name, realname);

    struct stat finfo;
    stat(argv[2], &finfo);
    info.size = finfo.st_size;

    sendto(udpfd, &info, sizeof(info), 0, (struct sockaddr *)&addr, len);

    char response;
    recvfrom(udpfd, &response, 1, 0, NULL, NULL);

    FILE *fp;
    char *buf;
    if(response == 'y')
    {
        // 马上进行TCP连接
        if(connect(tcpfd, (struct sockaddr *)&addr, len) == 0)
        {
            printf("连接成功\n");
        }

        fp = fopen(argv[2], "r");

        int bufsize = info.size > 1024 ? 1024 : info.size;
        buf = calloc(1, bufsize);

        int total = 0;
        while(1)
        {
            int n = fread(buf, 1, bufsize, fp);
            if(n == -1)
            {
                perror("读取文件内容失败");
                exit(0);
            }
            if(n == 0)
                break;

            int m = write(tcpfd, buf, n);
            if(m == -1)
            {
                perror("发送TCP数据失败");
                break;
            }
            total += m;
            printf("已发送%d个字节\n", total);
        }
    }
    else
    {
        printf("取消发文件\n");
        exit(0);
    }

    // 关闭、释放所有资源
    close(udpfd);
    close(tcpfd);
    free(buf);
    fclose(fp);

    return 0;
}
